package com.yangrd.airship.common.jpa;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import java.beans.PropertyDescriptor;
import java.util.HashSet;
import java.util.Set;


/**
 * description: BascController
 *
 * @author: yangrd
 * @date: 2021/7/3
 * @version: 1.0
 */
public abstract class BaseController<T,ID,D extends QuerydslPredicateExecutor<T> & JpaRepository<T,ID>> {

    protected D repository;

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public T save(@RequestBody T t) {
        return repository.save(t);
    }

    @DeleteMapping("/{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void delete(@PathVariable("id") ID id) {
        repository.deleteById(id);
    }

    @PutMapping("/{id}")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void update(@PathVariable("id") T dbData, @RequestBody T t) {
        BeanUtils.copyProperties(t, dbData);
        repository.saveAndFlush(dbData);
    }

    @GetMapping("/{id}")
    public T get(@PathVariable("id") T t) {
        return t;
    }

    @Autowired
    public void setRepository(D repository) {
        this.repository = repository;
    }

    /**
     * @author yangrd
     * @date 2018/8/30
     **/
    static class BeanUtils {

        /**
         * 只拷贝不为null的属性
         *
         * @param source the source bean
         * @param target the target bean
         * @throws BeansException if the copying failed
         */
        public static void copyProperties(Object source, Object target) throws BeansException {
            org.springframework.beans.BeanUtils.copyProperties(source, target, getNullPropertyNames(source));
        }

        private static String[] getNullPropertyNames(Object source) {
            final BeanWrapper src = new BeanWrapperImpl(source);
            PropertyDescriptor[] pds = src.getPropertyDescriptors();

            Set<String> emptyNames = new HashSet<>();
            for (PropertyDescriptor pd : pds) {
                Object srcValue = src.getPropertyValue(pd.getName());
                if (srcValue == null) {
                    emptyNames.add(pd.getName());
                }
            }
            String[] result = new String[emptyNames.size()];

            return emptyNames.toArray(result);
        }
    }

}
